#include<arpa/inet.h>
#include<netinet/in.h>
#include<ctype.h>
#include"wrap.h"
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/socket.h>
#include<sys/time.h>
/*
   使用select开发服务器端
		端口复用需要放在绑定的前面
 */



int main()
{
	//设置socket
	int lfd = Socket(AF_INET,SOCK_STREAM,0);

	//端口复用
	int opt = 1;
	setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(int));
	
	//绑定
	struct sockaddr_in serv;
	serv.sin_family = AF_INET;
	serv.sin_port = htons(6666);
	serv.sin_addr.s_addr = htonl(INADDR_ANY);
	Bind(lfd,(struct sockaddr*)&serv,sizeof(serv));

	//监听
	Listen(lfd,128);


	//将监听文件描述符加入监听文件描述符集合中去

	//定义fd_set类型的变量
	fd_set readfds;
	fd_set tmpfds;

	//清空readdfs和tmpfds集合
	FD_ZERO(&readfds);
	FD_ZERO(&tmpfds);

	//将lfd加入到readfds中委托内核监控
	FD_SET(lfd,&readfds);

	//等待时间发生
	int nready;
	int maxfd = lfd;
	int sockfd;
	int i;
	char buf[1024];
	int cfd;
	int n;
	while(1)
	{
		tmpfds = readfds; //连接集合
		/*
		   tmpfds是输入输出参数
		   输入是：告诉内核要监测哪些文件描述符
		   输出是：内核告诉应用程序有哪些文件描述符发生了变化
		 */
		nready = select(maxfd+1,&tmpfds,NULL,NULL,NULL);
		if(nready<0)
		{
			if(errno==EINTR)//被信号中断
			{
				continue;
			}
			break;
		}

		//有客户端连接请求
		if(FD_ISSET(lfd,&tmpfds))
		{
			//接受新的客户端连接请求
			cfd = Accept(lfd,NULL,NULL);

			//将cfd加入到readfds集合中
			FD_SET(cfd,&readfds);

			//修改内核的监测范围
			if(maxfd < cfd)
			{
				maxfd = cfd;
			}
			if(--nready==0)
			{
				continue;
			}
		}
		//有数据发来的情况
		for(i=lfd+1;i<=maxfd;i++)
		{
			sockfd = i;
			if(FD_ISSET(sockfd,&tmpfds))
			{
				//读数据
				memset(buf,0,sizeof(buf));
				n = Read(sockfd,buf,sizeof(buf));
				if(n<=0)
				{
					close(sockfd);
					//	将sockfd从readfds中删除
					FD_CLR(sockfd,&readfds);
				}
				else
				{
					printf("n==[%d],buf==[%s]\n",n,buf);
					int k = 0;
					for(k=0;k<n;k++)
					{
						buf[k] = toupper(buf[k]);
					}
					Write(sockfd,buf,n);
				}
				if(--nready==0)
				{
					continue;
				}
			}
		}
	}
	return 0;
}
